"""
配置管理器模块
统一管理所有环境变量配置，提供类型安全和默认值处理

作者: 架构重构优化
日期: 2025-01-05
"""

import os
import logging
from typing import Dict, Any, Optional
from dataclasses import dataclass
from dotenv import load_dotenv

logger = logging.getLogger(__name__)

@dataclass
class ModelConfig:
    """模型配置"""
    base_model: str = "gpt-4"
    backup_model: str = "deepseek-chat"
    openai_api_key: str = ""
    openai_api_base: str = ""
    deepseek_api_key: str = ""
    deepseek_api_base: str = ""
    temperature: float = 0.1
    max_tokens: int = 4000

@dataclass
class DingTalkConfig:
    """钉钉配置"""
    app_id: str = ""
    app_secret: str = ""
    union_id: str = ""

@dataclass
class RedisConfig:
    """Redis配置"""
    url: str = "redis://localhost:6380/0"
    max_connections: int = 10
    socket_timeout: int = 5
    socket_connect_timeout: int = 5
    retry_on_timeout: bool = True

@dataclass
class CacheConfig:
    """缓存配置"""
    memory_cache_size: int = 1000
    memory_ttl_seconds: int = 3600
    redis_ttl_seconds: int = 86400
    enabled: bool = True

@dataclass
class MemoryConfig:
    """记忆配置"""
    memory_key: str = "chat_history"
    enhanced_memory_enabled: bool = True
    max_token_limit: int = 3000
    summary_threshold: int = 80

@dataclass
class SystemConfig:
    """系统配置"""
    log_level: str = "INFO"
    debug_mode: bool = False
    max_workers: int = 4
    request_timeout: int = 30

class ConfigManager:
    """
    统一配置管理器
    负责加载、验证和提供所有系统配置
    """
    
    def __init__(self, env_file: Optional[str] = None):
        """
        初始化配置管理器
        
        Args:
            env_file: 环境变量文件路径，默认为 .env
        """
        # 加载环境变量
        if env_file:
            load_dotenv(env_file)
        else:
            load_dotenv()
        
        # 初始化各模块配置
        self.model = self._load_model_config()
        self.dingtalk = self._load_dingtalk_config()
        self.redis = self._load_redis_config()
        self.cache = self._load_cache_config()
        self.memory = self._load_memory_config()
        self.system = self._load_system_config()
        
        # 验证配置
        self._validate_config()
        
        logger.info("配置管理器初始化完成")

    def _load_model_config(self) -> ModelConfig:
        """加载模型配置"""
        return ModelConfig(
            base_model=os.getenv("BASE_MODEL", "gpt-4"),
            backup_model=os.getenv("BACKUP_MODEL", "deepseek-chat"),
            openai_api_key=os.getenv("OPENAI_API_KEY", ""),
            openai_api_base=os.getenv("OPENAI_API_BASE", ""),
            deepseek_api_key=os.getenv("DEEPSEEK_API_KEY", ""),
            deepseek_api_base=os.getenv("DEEPSEEK_API_BASE", ""),
            temperature=float(os.getenv("MODEL_TEMPERATURE", "0.1")),
            max_tokens=int(os.getenv("MODEL_MAX_TOKENS", "4000"))
        )

    def _load_dingtalk_config(self) -> DingTalkConfig:
        """加载钉钉配置"""
        return DingTalkConfig(
            app_id=os.getenv("DINGDING_ID", ""),
            app_secret=os.getenv("DINGDING_SECRET", ""),
            union_id=os.getenv("DINGDING_UNION_ID", "")
        )

    def _load_redis_config(self) -> RedisConfig:
        """加载Redis配置"""
        return RedisConfig(
            url=os.getenv("REDIS_URL", "redis://localhost:6380/0"),
            max_connections=int(os.getenv("REDIS_MAX_CONNECTIONS", "10")),
            socket_timeout=int(os.getenv("REDIS_SOCKET_TIMEOUT", "5")),
            socket_connect_timeout=int(os.getenv("REDIS_CONNECT_TIMEOUT", "5")),
            retry_on_timeout=os.getenv("REDIS_RETRY_ON_TIMEOUT", "true").lower() == "true"
        )

    def _load_cache_config(self) -> CacheConfig:
        """加载缓存配置"""
        return CacheConfig(
            memory_cache_size=int(os.getenv("MEMORY_CACHE_SIZE", "1000")),
            memory_ttl_seconds=int(os.getenv("MEMORY_TTL_SECONDS", "3600")),
            redis_ttl_seconds=int(os.getenv("REDIS_TTL_SECONDS", "86400")),
            enabled=os.getenv("CACHE_ENABLED", "true").lower() == "true"
        )

    def _load_memory_config(self) -> MemoryConfig:
        """加载记忆配置"""
        return MemoryConfig(
            memory_key=os.getenv("MEMORY_KEY", "chat_history"),
            enhanced_memory_enabled=os.getenv("ENHANCED_MEMORY", "true").lower() == "true",
            max_token_limit=int(os.getenv("MEMORY_MAX_TOKENS", "3000")),
            summary_threshold=int(os.getenv("MEMORY_SUMMARY_THRESHOLD", "80"))
        )

    def _load_system_config(self) -> SystemConfig:
        """加载系统配置"""
        return SystemConfig(
            log_level=os.getenv("LOG_LEVEL", "INFO"),
            debug_mode=os.getenv("DEBUG_MODE", "false").lower() == "true",
            max_workers=int(os.getenv("MAX_WORKERS", "4")),
            request_timeout=int(os.getenv("REQUEST_TIMEOUT", "30"))
        )

    def _validate_config(self):
        """验证配置的有效性"""
        errors = []
        
        # 验证必需的配置
        if not self.model.openai_api_key and not self.model.deepseek_api_key:
            errors.append("至少需要配置一个 API 密钥 (OPENAI_API_KEY 或 DEEPSEEK_API_KEY)")
        
        if not self.dingtalk.app_id or not self.dingtalk.app_secret:
            logger.warning("钉钉配置不完整，钉钉功能可能不可用")
        
        # 验证数值范围
        if self.model.temperature < 0 or self.model.temperature > 2:
            errors.append("模型温度值应在 0-2 之间")
        
        if self.cache.memory_cache_size <= 0:
            errors.append("内存缓存大小必须大于 0")
        
        if errors:
            error_msg = "配置验证失败:\n" + "\n".join(f"- {error}" for error in errors)
            raise ValueError(error_msg)
        
        logger.info("配置验证通过")

    def get_env_dict(self) -> Dict[str, str]:
        """获取环境变量字典（用于设置 os.environ）"""
        env_dict = {}
        
        # 模型配置
        if self.model.openai_api_key:
            env_dict["OPENAI_API_KEY"] = self.model.openai_api_key
        if self.model.openai_api_base:
            env_dict["OPENAI_API_BASE"] = self.model.openai_api_base
        if self.model.deepseek_api_key:
            env_dict["DEEPSEEK_API_KEY"] = self.model.deepseek_api_key
        if self.model.deepseek_api_base:
            env_dict["DEEPSEEK_API_BASE"] = self.model.deepseek_api_base
        
        return env_dict

    def to_dict(self) -> Dict[str, Any]:
        """将配置转换为字典格式"""
        return {
            "model": self.model.__dict__,
            "dingtalk": self.dingtalk.__dict__,
            "redis": self.redis.__dict__,
            "cache": self.cache.__dict__,
            "memory": self.memory.__dict__,
            "system": self.system.__dict__
        }

    def __str__(self) -> str:
        """字符串表示（隐藏敏感信息）"""
        config_dict = self.to_dict()
        
        # 隐藏敏感信息
        sensitive_keys = ["api_key", "app_secret", "password"]
        for section in config_dict.values():
            if isinstance(section, dict):
                for key, value in section.items():
                    if any(sensitive in key.lower() for sensitive in sensitive_keys):
                        if value:
                            section[key] = "***"
        
        return f"ConfigManager({config_dict})"

# 全局配置实例
_config_instance = None

def get_config() -> ConfigManager:
    """获取全局配置实例（单例模式）"""
    global _config_instance
    if _config_instance is None:
        _config_instance = ConfigManager()
    return _config_instance

def reset_config():
    """重置全局配置实例（用于测试）"""
    global _config_instance
    _config_instance = None
